package com.msh.frame.client.util;

import com.alibaba.fastjson.JSON;
import com.msh.frame.client.define.StringDef;
import com.msh.frame.interfaces.ILayer;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * code处理 方法中默认定长为每一层级3个数字
 */
public class LayerCodeUtil {
  private static final String CODE_SPLIT = StringDef.COLON;
  public static final String DEFAULT_FIRST_CODE = "1";

  /**
   * 比较器
   */
  public static final Comparator<ILayer> COMPARATOR = new Comparator<ILayer>() {
    @Override
    public int compare(ILayer o1, ILayer o2) {
      String layerCode1 = o1.getLayerCode();
      String layerCode2 = o2.getLayerCode();
      if(null == layerCode1){
        return -1;
      }
      if(null == layerCode2){
        return 1;
      }
      String[] split1 = layerCode1.split(CODE_SPLIT);
      String[] split2 = layerCode2.split(CODE_SPLIT);
      int len1 = split1.length;
      int len2 = split2.length;
      int i=0;
      for(;i<len1 && i<len2; i++){
        int length1 = split1[i].length();
        int length2 = split2[i].length();
        int len = length1 - length2;
        int compare = 0 != len ? len : split1[i].compareTo(split2[i]);
        if(0 != compare){
          return compare;
        }
      }
      if(i == len1){
        return -1;
      }
      if(i == len2){
        return 1;
      }
      return 0;
    }
  };

  public static String getFirstChildrenCode(String parentLayerCode) {
    return parentLayerCode + DEFAULT_FIRST_CODE + CODE_SPLIT;
  }

  /**
   * 获取下一个code
   */
  public static String getNextCode(String layerCode) {
    String[] split = layerCode.split(CODE_SPLIT);
    int lastCodeIdx = split.length-1;
    String changeCode = split[lastCodeIdx];
    if(StringUtils.isEmpty(changeCode)){
      changeCode = DEFAULT_FIRST_CODE;
    }else {
      changeCode = nextNumStr(changeCode);
    }
    split[lastCodeIdx] = changeCode;
    return Stream.of(split).collect(Collectors.joining(CODE_SPLIT)) + CODE_SPLIT;
  }

  /**
   * 获取默认定长code的层级
   */
  public static int getLayer(String layerCode) {
    return layerCode.split(CODE_SPLIT).length;
  }

  /**
   * 获取其父级code
   *
   * @param layerCode 输入layerCode
   * @return 父级code
   */
  public static String getParentCode(String layerCode) {
    int i = layerCode.substring(0, layerCode.length()-1).lastIndexOf(CODE_SPLIT);
    if(i <= 0){
      return StringDef.EMPTY;
    }
    return layerCode.substring(0, i+1);
  }

  /**
   * 获取所有父级的layerCode
   * @param layerCode
   * @return
   */
  public static Set<String> getAllParentLayerCode(String layerCode){
    int i = layerCode.substring(0, layerCode.length()-1).lastIndexOf(CODE_SPLIT);
    if(i<0){
      return Collections.emptySet();
    }
    Set<String> set = new HashSet<>();
    while(i>0){
      layerCode = layerCode.substring(0, i);
      set.add(layerCode + CODE_SPLIT);
      i = layerCode.lastIndexOf(CODE_SPLIT);
    }
    set.add(layerCode + CODE_SPLIT);
    return set;
  }

  /**
   * 获取顶级LayerCode
   * @param layerCodes 例 ("1:1:1:", "1:1:2:", "1:1:", "2:1:1:", "2:2:1:", "2:", "3:1:2:")
   * @return 例返回 ("1:1:","2:","3:1:2:")
   */
  public static Set<String> getTopLayerCode(Collection<String> layerCodes){
    if(CollectionUtils.isEmpty(layerCodes)){
      return Collections.emptySet();
    }
    if(1 == layerCodes.size()){
      return new HashSet<>(layerCodes);
    }
    List<String> list = layerCodes.stream()
            .sorted(Comparator.comparing((a)->a.split(CODE_SPLIT).length))
            .collect(Collectors.toCollection(LinkedList::new));
    Set<String> res = new HashSet<>();
    while(true){
      String item = list.get(0);
      res.add(item);
      list.remove(0);
      if(list.size() == 0){
        break;
      }
      Iterator<String> iterator = list.iterator();
      while(iterator.hasNext()){
        String next = iterator.next();
        if(next.startsWith(item)){
          iterator.remove();
        }
      }
    }
    return res;
  }

  private static String nextNumStr(String str){
    return String.valueOf(Integer.valueOf(str) + 1);
  }

  /**
   * 相同父级对比(只能在相同父级时适用)
   * @param layerCode1
   * @param layerCode2
   * @return
   */
  public static int compareSameParent(String layerCode1, String layerCode2) {
    int length1 = layerCode1.length();
    int length2 = layerCode2.length();
    int len = length1 - length2;
    return 0 != len ? len : layerCode1.compareTo(layerCode2);
  }


  /**
   * 获取相同父节点下的下一个层级编码
   * @param parentLayerCode 父节点layerCode
   * @param list 父节点下一级所有layerCode
   * @return
   * @param <T>
   */
  public static <T extends ILayer> String getSameParentNextLayerCode(String parentLayerCode, List<T> list){
    if(CollectionUtils.isEmpty(list)){
      return LayerCodeUtil.getFirstChildrenCode(parentLayerCode);
    }else if(list.size() == 1){
      return LayerCodeUtil.getNextCode(list.get(0).getLayerCode());
    }
    list = list.stream().sorted(((o1, o2) -> compareSameParent(o1.getLayerCode(), o2.getLayerCode())))
            .collect(Collectors.toList());
    return LayerCodeUtil.getNextCode(list.get(list.size()-1).getLayerCode());
  }

  public static void main(String[] args) {
    System.out.println(getNextCode("1:"));
    System.out.println(getNextCode("1:1:"));
    System.out.println(getNextCode("1:2222:332324234:"));
    System.out.println(getLayer("1:"));
    System.out.println(getLayer("1:1:"));
    System.out.println(getLayer("1:2222:332324234:"));
    System.out.println(getParentCode("1:"));
    System.out.println(getParentCode("1:1:"));
    System.out.println(getParentCode("1:2222:332324234:"));
    System.out.println(JSON.toJSONString(getAllParentLayerCode("1:")));
    System.out.println(JSON.toJSONString(getAllParentLayerCode("1:2222:332324234:")));
    List<String> list = Arrays.asList("1:1:1:", "1:1:2:", "1:1:", "2:1:1:", "2:2:1:", "2:", "3:1:2:");
    Set<String> topLayerCode = getTopLayerCode(list);
    System.out.println(JSON.toJSONString(topLayerCode));
    list = Arrays.asList("1:1:1:", "1:1:21:", "1:1:12:", "1:1:14:", "1:1:44:", "1:1:84:", "1:1:11111:");
    System.out.println(JSON.toJSONString(list.stream().sorted(LayerCodeUtil::compareSameParent).collect(Collectors.toList())));
  }
}
